/********************************************************************************
* 
*	Project Name : S3C6410 Validation
*
*	Copyright 2008 by Samsung Electronics, Inc.
*	All rights reserved.
*
*	Project Description :
*		This software is only for verifying functions of the S3C6410.
*		Anybody can use this software without our permission.
*  
*--------------------------------------------------------------------------------
* 
*	File Name : PCM_test.c
*  
*	File Description :
*
*	Author	: Sung-Hyun, Na
*	Dept. : AP Development Team
*	Created Date : 2008/02/01
*	Version : 0.2 
* 
*	History
*	- Version 0.1 (2007/03/16)
*	  -> Available with AK2440 PCM Codec.
*   - Version 0.2 (2007/04/
*	  -> Available with 
*********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6410.h"
#include "system.h"
#include "sysc.h"
#include "intc.h"
#include "gpio.h"
#include "iic.h"
#include "dma.h"

#include "pcm.h"
#include "ac97.h"
#include "i2s.h"

static PCM_Infor 	g_oPCMInfor[AUDIO_NUM];

static void PCM_Outp32(AUDIO_PORT ePort, PCM_SFR offset, u32 x);
static void PCM_Outp16(AUDIO_PORT ePort, PCM_SFR offset, u32 x);
static u32  PCM_Inp32(AUDIO_PORT ePort, PCM_SFR offset);
static u16 PCM_Inp16(AUDIO_PORT ePort, PCM_SFR offset);

//////////
// Function Name : PCM_Outp32
// Function Description : This function write 32 bit value to SFR
// Input : 	ePort - PCM Port Number 
//			offset - SFR Offset
//			x - Register Value
// Output :	None
// Version : v0.0
static void PCM_Outp32(AUDIO_PORT ePort, PCM_SFR offset, u32 x) 
{
	if (ePort == AUDIO_PORT0)
		Outp32(PCM0_BASE+offset, x);
	else
		Outp32(PCM1_BASE+offset, x);
}

//////////
// Function Name : PCM_Outp16
// Function Description : This function write 16 bit value to SFR
// Input : 	ePort - PCM Port Number 
//			offset - SFR Offset
//			x - Register Value
// Output :	None
// Version : v0.0
static void PCM_Outp16(AUDIO_PORT ePort, PCM_SFR offset, u32 x) 
{
	if (ePort == AUDIO_PORT0)
		Outp16(PCM0_BASE+offset, x);
	else
		Outp16(PCM1_BASE+offset, x);
}

//////////
// Function Name : PCM_Inp32
// Function Description : This function read 32 bit value to SFR
// Input : 	ePort - PCM Port Number 
//			offset - SFR Offset			
// Output :	u32 - SFR Register Value
// Version : v0.0
static u32  PCM_Inp32(AUDIO_PORT ePort, PCM_SFR offset)
{
	if (ePort == AUDIO_PORT0)
		return Inp32(PCM0_BASE+offset);
	else 
		return Inp32(PCM1_BASE+offset);
}

//////////
// Function Name : PCM_Inp16
// Function Description : This function read 16 bit value to SFR
// Input : 	ePort - PCM Port Number 
//			offset - SFR Offset			
// Output :	u16 - SFR Register Value
// Version : v0.0
static u16 PCM_Inp16(AUDIO_PORT ePort, PCM_SFR offset)
{
	if (ePort == AUDIO_PORT0)
		return Inp16(PCM0_BASE+offset);
	else
		return Inp16(PCM1_BASE+offset);
}

//////////
// Function Name : PCM_Init
// Function Desctiption : This fucntion initialize S3C6410 Information sturcture of PCM Interface.
// Input : 	ePort - PCM Port Number 
// Output : None
// Version : 0.1
// Author : Sung-Hyun, Na
void PCM_Init(AUDIO_PORT ePort)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if(ePort == AUDIO_PORT0)
	{
		pInfor->m_uNumInt 			= NUM_PCM0;	
		pInfor->m_uNumDma			= NUM_DMA0;		
		pInfor->m_eDmaUnit			= DMA0;		
		pInfor->m_eDmaTxCh			= DMA_A;
		pInfor->m_eDmaRxCh			= DMA_B;
		//Sample Rate
		pInfor->m_uSamplingRate 		= 16000;
		//PCM Shift Clock
		pInfor->m_uPCMSClk 			= 768000;			
		// Rec Address & Data Size
		pInfor->m_uRecSize			= PCM_REC_LEN;		
		pInfor->m_pRecAddr 			= (u16* )0x5100002c;		
		// Play Address & Data Size
		pInfor->m_uPlaySize			= PCM_REC_LEN;
		pInfor->m_pPCMTxAddr 			= (u16* )0x5100002c;
		//IP Operation
		pInfor->m_ePCMClkSrc 		= PCM_MOUT_EPLL;
		pInfor->m_eTXMSBPosition 	= AFTER_PCMSYNC_HIGH;
		pInfor->m_eRXMSBPosition 	= AFTER_PCMSYNC_HIGH;
		pInfor->m_uRXFIFODipstick		= 0x20;
		pInfor->m_uTXFIFODipstick		= 0x8;			
		pInfor->m_uIntAspects		= RX_FIFO_ALMOST_FULL | TXFIFO_ALMOST_EMPTY;
		//SMDK Configuration
		pInfor->m_uCodec			= WM8990;
		pInfor->m_eLine				= CodecPort_1st;		
				
	}

	else if(ePort == AUDIO_PORT1)
	{
		pInfor->m_uNumInt 			= NUM_PCM1;
		pInfor->m_uNumDma			= NUM_DMA1;		
		pInfor->m_eDmaUnit			= DMA1;	
		pInfor->m_eDmaTxCh			= DMA_A;
		pInfor->m_eDmaRxCh			= DMA_B;
		//Sample Rate
		pInfor->m_uSamplingRate 		= 16000;
		//PCM Shift Clock
		pInfor->m_uPCMSClk 			= 768000;			
		// Rec Address & Data Size
		pInfor->m_uRecSize			= PCM_REC_LEN;		
		pInfor->m_pRecAddr 			= (u16* )0x5100002c;		
		// Play Address & Data Size
		pInfor->m_uPlaySize			= PCM_REC_LEN;
		pInfor->m_pPCMTxAddr 			= (u16* )0x5100002c;
		//IP Operation
		pInfor->m_ePCMClkSrc 		= PCM_MOUT_EPLL;
		pInfor->m_eTXMSBPosition 	= AFTER_PCMSYNC_HIGH;
		pInfor->m_eRXMSBPosition 	= AFTER_PCMSYNC_HIGH;
		pInfor->m_uRXFIFODipstick		= 0x20;
		pInfor->m_uTXFIFODipstick		= 0x8;			
		pInfor->m_uIntAspects		= RX_FIFO_ALMOST_FULL | TXFIFO_ALMOST_EMPTY;
		//SMDK Configuration
		pInfor->m_uCodec			= WM8580;
		pInfor->m_eLine				= CodecPort_2nd;		
		
	}	
	//Put Data PCMCON
	PCMCTL_PutData(ePort);		
	PCMIRQCTL_SetIRQMode(ePort, pInfor->m_uIntAspects, ENABLE);
}

//////////
// Function Name : PCM_GetInfor
// Function Description : This function gets address of PCM inforamtion structure.
// Input : 	ePort - PCM Port Number 
// Output :	PCM_Infor* - Address of PCM Information structure
// Version : v0.1
PCM_Infor* PCM_GetInfor(AUDIO_PORT ePort)
{
	if ( ePort == AUDIO_PORT0 )
		return &(g_oPCMInfor[0]);
	else if ( ePort == AUDIO_PORT1 )
		return &(g_oPCMInfor[1]);
	else
	{
		UART_Printf("S3C6410 dose not support Port%d\n",ePort);
		Assert(0);
		return FALSE;
	}
}

//////////
// Function Name : PCM_SetInfor
// Function Description : This function sets PCM information structure.
// Input : 	ePort - PCM Port Number 
// 			PCM_Infor* - address of PCM structure 
// Output :	None
// Version : v0.1
void PCM_SetInfor(AUDIO_PORT ePort, PCM_Infor* peInfor)
{
	 if (ePort == AUDIO_PORT1)
	 	memcpy(	(u32 *)(&g_oPCMInfor[AUDIO_PORT1]), (u32 *)peInfor, sizeof(PCM_Infor));
	else  if (ePort == AUDIO_PORT0)
		memcpy(	(u32 *)(&g_oPCMInfor[AUDIO_PORT0]), (u32 *)peInfor, sizeof(PCM_Infor));
	else
	{	
		Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
		Assert(0);
	}
}

//////////
// Function Name : PCM_CpyI2SInfor
// Function Description : This function copy PCM information structure to Memory
// Input : 	ePort - PCM Port Number 
// 			PCM_Infor* - address of PCM structure 
// Output :	None
// Version : v0.1
u8 PCM_CpyInfor(AUDIO_PORT ePort, u32 *peTemp)
{
	if (ePort == AUDIO_PORT0)
	{
		memcpy(peTemp, (u32 *)(&g_oPCMInfor[AUDIO_PORT0]), sizeof(PCM_Infor));
		return TRUE;
	}
	else if(ePort == AUDIO_PORT1)
	{
		memcpy(peTemp, (u32 *)(&g_oPCMInfor[AUDIO_PORT1]), sizeof(PCM_Infor));
		return TRUE;
	}
	else
	{
		Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
		Assert(0);
		return FALSE;
	}
}

//////////
// Function Name : PCM_SetAddr
// Function Description : This function set Memory Buffer
// Input : 	ePort - PCM Port Number 
// 			PCM_IFMODE - RX or TX
// 			u16* - New Address
//			u32 - Data size
// Output :	None
// Version : v0.0
void PCM_SetAddr(AUDIO_PORT ePort, PCM_IFMODE  eCh, u16* pAddr, u32 uDataSize)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if ( eCh == PCM_RX )
	{
		pInfor->m_pRecAddr = (u16 *)pAddr;
		pInfor->m_uRecSize = uDataSize;
	}
	else if ( eCh == PCM_TX )
	{
		pInfor->m_pPCMTxAddr = (u16 *)pAddr;
		pInfor->m_uPlaySize = uDataSize;

	}
	else if ( eCh == PCM_TXRX )
	{
		pInfor->m_pRecAddr = (u16 *)pAddr;
		pInfor->m_uRecSize = uDataSize;
		pInfor->m_pPCMTxAddr = (u16 *)pAddr;
		pInfor->m_uPlaySize = uDataSize;
	}
	else 
		Assert(0);	
}

//////////
// Function Name : PCM_PutDataMem
// Function Description : This function put data PCM Data Memory Buffer
// Input : 	ePort - PCM Port Number 
// 			I2S_IFMode - RX or TX
// 			u32 - PCM Data
// Output :	u32* - Current Address of PCM Data Buffer
// Version : v0.0
u16* PCM_PutDataMem(AUDIO_PORT ePort, PCM_IFMODE  eCh, u32 uData)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if ( eCh == RXOnly )
	{
		*(pInfor->m_pMemI2SRx++) = uData;
		return pInfor->m_pMemI2SRx;
	}
	else if ( eCh == TXOnly )
	{
		*(pInfor->m_pMemI2STx++) = uData;
		return pInfor->m_pMemI2STx;
	}
	else
	{
		Assert(0);
		return FALSE;
	}	
}

//////////
// Function Name : PCM_PopDataMem
// Function Description : This function pop data PCM Data in the Memory Buffer
// Input : 	ePort - Audio Controller Port Number 
// 			I2S_IFMode - RX or TX
// Output :	u32 - PCM Data
// Version : v0.0
u16 PCM_PopDataMem(AUDIO_PORT ePort, PCM_IFMODE eCh)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	u32 uData;
	if ( eCh == RXOnly )
		uData = *(pInfor->m_pMemI2SRx++);		
	else if ( eCh == TXOnly )
		uData = *(pInfor->m_pMemI2SRx++);
	else
	{
		Assert(0);
		return FALSE;
	}	
	return uData;
}

//////////
// Function Name : PCM_InitCodecDataIn
// Function Description : This function initialize Audio Codec for PCM I/F.
// Input : 	ePort - PCM Port Number 
// 			uCodecId - Codec ID
// 			eCodecPort - connecting Codec Port to interface AP Audio Port
// Output :	u8 - TRUE/FALSE
// Version : v0.0
u8 PCM_InitCodecDataIn(AUDIO_PORT ePort, u32 uCodecId, CodecPort eCodecPort)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if (uCodecId == WM8753)		
	{
		// Codec Initialization for WM8753
		I2S_Init((AUDIO_PORT)(~ePort & 0x1));							// I2SCDCLK Out for Master Clock of WM8753 using another audio port
		I2S_InitPort((AUDIO_PORT)((~ePort) & 0x1));
		I2S_SetCDCLKOut((AUDIO_PORT)((~ePort) & 0x1), (I2S_IFMode) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
		WM8753_CodecInitPCMIn(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_2nd);//set external codec
		return TRUE;
	}
	else if (uCodecId == WM8990)
	{
		if ( ePort == AUDIO_PORT0)
		{
			// I2SCDCLK Out for Master Clock of WM8990 using audio port0
			I2S_Init(ePort);		
			I2S_SetCDCLKPort(ePort);
			I2S_SetCDCLKOut(ePort, (I2S_CLKSRC) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
			// Codec Initialization for WM8990
			WM8990_CodecInitPCMIn(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_1st);//set external codec
			return TRUE;
		}
		else
		{
			UART_Printf("This path is not available for recoding!!\n");
			Assert(0);
			return FALSE;
		}
	}
	else if (uCodecId == WM9713)
	{
		// Not yet
		WM9713_CodecInitPCMIn(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_2nd);//set external codec
		return FALSE;
	}
	else if (uCodecId  == WM8580)
	{
		#if(WM8580MASTERCLK == CDCLK_I2SMULTI)
			I2SMULTI_Init(AUDIO_PORT0);
			I2SMULTI_InitPort(AUDIO_PORT0);	
			I2SMULTI_CDCLKOut(AUDIO_PORT0, I2SMulti_GetInfor(AUDIO_PORT0));
		#elif(WM8580MASTERCLK == CDCLK_I2SCDCLK)
			I2S_Init(ePort);
			I2S_SetCDCLKPort(ePort);
			I2S_SetCDCLKOut(ePort, (I2S_IFMode) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
		#endif		
		WM8580_CodecInitPCMIn(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_2nd);
		return TRUE;
	}
	else
		Assert(0);
	return FALSE;	
}

//////////
// Function Name : PCM_InitCodecDataOut
// Function Description : This function put data PCM Data Memory Buffer
// Input : 	ePort - PCM Port Number 
// 			uCodecId - RX or TX
// 			eCodecPort - PCM Data
// Output :	u8 - Current Address of PCM Data Buffer
// Version : v0.0
u8 PCM_InitCodecDataOut(AUDIO_PORT ePort, u32 uCodecId, CodecPort eCodecPort)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if (uCodecId == WM8753)		
	{
		// I2SCDCLK Out for Master Clock of WM8753 using another audio port
		I2S_Init((AUDIO_PORT)(~ePort & 0x1));		
		I2S_InitPort((AUDIO_PORT)((~ePort) & 0x1));
		I2S_SetCDCLKOut((AUDIO_PORT)((~ePort) & 0x1), (I2S_CLKSRC) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
		// Codec Initialization for WM8753
		WM8753_CodecInitPCMOut(pInfor->m_eTXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, CodecPort_2nd);
	}
	else if (uCodecId == WM8990)
	{
		// I2SCDCLK Out for Master Clock of WM8990 using audio port0
		I2S_Init(AUDIO_PORT0);		
		I2S_SetCDCLKPort(AUDIO_PORT0);
		I2S_SetCDCLKOut(AUDIO_PORT0, (I2S_CLKSRC) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
		// Codec Initialization for WM8990
		if ( ePort == AUDIO_PORT0)
			WM8990_CodecInitPCMOut(pInfor->m_eTXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, CodecPort_1st);//set external codec
		else 
			WM8990_CodecInitPCMOut(pInfor->m_eTXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, CodecPort_2nd);//set external codec
	}
	else if (uCodecId == WM8580)
	{
		#if(WM8580MASTERCLK == CDCLK_I2SMULTI)
			I2SMULTI_Init(AUDIO_PORT0);
			I2SMULTI_InitPort(AUDIO_PORT0);	
			I2SMULTI_CDCLKOut(AUDIO_PORT0, I2SMulti_GetInfor(AUDIO_PORT0));	
		#elif(WM8580MASTERCLK == CDCLK_I2SCDCLK)
			I2S_Init(ePort);
			I2S_SetCDCLKPort(ePort);
			I2S_SetCDCLKOut(ePort, pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
		#endif		
		WM8580_CodecInitPCMOut(pInfor->m_eTXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, CodecPort_2nd);
	}
	else		
		Assert(0);
}

//////////
// Function Name : PCM_InitCodecDataIn
// Function Description : This function initialize Audio Codec for PCM I/F.
// Input : 	ePort - PCM Port Number 
// 			I2S_IFMode - RX or TX
// 			u32 - PCM Data
// Output :	u8 - Right initialization.
// Version : v0.0
u8 PCM_InitCodecFullDuplex(AUDIO_PORT ePort, u32 uCodecId, CodecPort eCodecPort)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if (uCodecId == WM8753)		
	{
		// Codec Initialization for WM8753
		I2S_Init((AUDIO_PORT)(~ePort & 0x1));							// I2SCDCLK Out for Master Clock of WM8753 using another audio port
		I2S_InitPort((AUDIO_PORT)((~ePort) & 0x1));
		I2S_SetCDCLKOut((AUDIO_PORT)((~ePort) & 0x1), (I2S_IFMode) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
		WM8753_CodecInitPCMIn(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_2nd);//set external codec
		return TRUE;
	}
	else if (uCodecId == WM8990)
	{
		if ( ePort == AUDIO_PORT0)
		{
			// I2SCDCLK Out for Master Clock of WM8990 using audio port0
			I2S_Init(ePort);		
			I2S_SetCDCLKPort(ePort);
			I2S_SetCDCLKOut(ePort, (I2S_CLKSRC) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
			// Codec Initialization for WM8990
			WM8990_CodecInitFullDuplex(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_1st);//set external codec
			return TRUE;
		}
		else
		{
			UART_Printf("This path is not available for recoding!!\n");
			Assert(0);
			return FALSE;
		}
	}
	else if (uCodecId == WM9713)
	{
		WM9713_CodecInitPCMIn(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_2nd);//set external codec
	}
	else if (uCodecId  == WM8580)
	{
		#if(WM8580MASTERCLK == CDCLK_I2SMULTI)
			I2SMULTI_Init(AUDIO_PORT0);
			I2SMULTI_InitPort(AUDIO_PORT0);	
			I2SMULTI_CDCLKOut(AUDIO_PORT0, I2SMulti_GetInfor(AUDIO_PORT0));
		#elif(WM8580MASTERCLK == CDCLK_I2SCDCLK)
			I2S_Init(ePort);
			I2S_SetCDCLKPort(ePort);
			I2S_SetCDCLKOut(ePort, (I2S_IFMode) pInfor->m_ePCMClkSrc, pInfor->m_uSamplingRate, RFS_256fs);
		#endif		
		WM8580_CodecInitPCMIn(pInfor->m_eRXMSBPosition, pInfor->m_uSamplingRate, Master, Word16, LINEIN, CodecPort_2nd);
	}
	else
		Assert(0);
}



//////////
// Function Name : PCM_InitPort
// Function Description : This function set GPIO for PCM Interface
// Input : 	ePort - PCM Port Number 
// Output :	None
// Version : v0.0
void PCM_InitPort(AUDIO_PORT ePort)
{
	switch(ePort)
	{
		case AUDIO_PORT0:
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_1, 0x1);	// PCM0 CDCLK Pull Down Enable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_1, 0x2);		// PCM0 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_0, 0x0);	// PCM0 SCLK Pull Up/Down Disable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_0, 0x2);		// PCM0 SCLK
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_2, 0x0);	// PCM0 LRCLK Pull Up/Down Disable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_2, 0x2);		// PCM0 LRCLK
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_3, 0x0);	// PCM0 DIN Pull Up/Down Disable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_3, 0x2);		// PCM0 DIN
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_4, 0x0);	// PCM0 DOUT Pull Up/Down Disable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_4, 0x2);		// PCM0 DOUT
			break;
		case AUDIO_PORT1 :
			GPIO_SetPullUpDownAll(eGPIO_E, 0x0);
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_1, 0x1);	// PCM1 CDCLK Pull Down Enable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_1, 0x2);		// PCM1 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_0, 0x0);	// PCM1 SCLK Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_0, 0x2);		// PCM1 SCLK
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_2, 0x0);	// PCM1 LRCLK Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_2, 0x2);		// PCM1 LRCLk
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_3, 0x0);	// PCM1 DIN Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_3, 0x2);		// PCM1 DIN
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_4, 0x0);	// PCM1 DOUT Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_4, 0x2);		// PCM1 DOUT		
			break;
		default :
			Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
			Assert(0);
			break;
	}
	Delay(1000);
}

//////////
// Function Name : PCM_ClosePort
// Function Description : This function closes PCM Interface Port.
// Input : 	ePort - PCM Port Number 
// Output :	None
// Version : v0.0
void PCM_ClosePort(AUDIO_PORT ePort)
{
	if (ePort == AUDIO_PORT0)
	{
		//Set GPD: PCM Port
		GPIO_SetFunctionAll(eGPIO_D, 0x0, 0); 
		GPIO_SetPullUpDownAll(eGPIO_D, 0x0);	
	}					
	else if (ePort == AUDIO_PORT1)
	{
		//Set GPE: PCM Port
		GPIO_SetFunctionAll(eGPIO_E, 0x0, 0); 
		GPIO_SetPullUpDownAll(eGPIO_E, 0x0);				
	}
	Delay(1000);
}


//////////
// Function Name : PCM_InitDMA
// Function Description : 
//   This function initialize DMA Controller for PCM Interface
// Input : 	ePort ->  PCM Controller
//			eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
// Example 
// I2S_InitDMA(AUDIO_PORT1, PCM_RX);
void PCM_InitDMA(AUDIO_PORT ePort, PCM_IFMODE eIFMode)
{
	PCM_Infor* pInfor	 = PCM_GetInfor(ePort);
	DMA_CH		eDmaCh;
	DMAC*		pPcmDma;
	DMASELECT_eID eDmaId;
	DREQ_SRC eDmaReqSrc;
	u32 uDmaSrcAddr;
	u8 usDmaSrcFix;
	DREQ_SRC eDmaReqDst;
	u32 uDmaDstAddr;
	u8 usDmaDstFix;	
	s32 sDmaTransfeSize;
	if (ePort == AUDIO_PORT0)
	{
		if ( eIFMode == PCM_RX )
		{
			eDmaCh		= pInfor->m_eDmaRxCh;
			pPcmDma	= &(pInfor->m_oPcmRxDma);
			eDmaId		= eSEL_PCM0_RX;
			eDmaReqSrc	= DMA0_PCM0_RX;				
			uDmaSrcAddr	= PCM0_BASE + rPCMRXFIFO;
			usDmaSrcFix	= TRUE;
			eDmaReqDst	= MEM;
			uDmaDstAddr= (u32) pInfor->m_pRecAddr;
			sDmaTransfeSize = pInfor->m_uRecSize/2;
			usDmaDstFix	= FALSE;
		}
		else if ( eIFMode == PCM_TX )
		{
			eDmaCh		= pInfor->m_eDmaTxCh;
			pPcmDma	= &(pInfor->m_oPcmTxDma);
			eDmaId		= eSEL_PCM0_TX;
			eDmaReqSrc	= MEM;
			eDmaReqDst	= DMA0_PCM0_TX;
			uDmaSrcAddr	= (u32) pInfor->m_pPCMTxAddr;
			sDmaTransfeSize = pInfor->m_uPlaySize/2;
			usDmaSrcFix	= FALSE;
			uDmaDstAddr= PCM0_BASE + rPCMTXFIFO;
			usDmaDstFix	= TRUE;		
		}
		else
		{
			eDmaCh		= pInfor->m_eDmaRxCh;
			pPcmDma	= &(pInfor->m_oPcmRxDma);
			eDmaId		= eSEL_PCM0_RX;
			eDmaReqSrc	= DMA0_PCM0_RX;	
			uDmaSrcAddr	= PCM0_BASE + rPCMRXFIFO;
			usDmaSrcFix	= TRUE;
			eDmaReqDst	= DMA0_PCM0_TX;
			uDmaDstAddr= PCM0_BASE + rPCMTXFIFO;
			sDmaTransfeSize = 16;
			usDmaSrcFix	= TRUE;
		}
	}	
	else if ( ePort == AUDIO_PORT1)
	{
		if ( eIFMode == PCM_RX )
		{
			eDmaCh		= pInfor->m_eDmaRxCh;
			pPcmDma	= &(pInfor->m_oPcmRxDma);
			eDmaId		= eSEL_PCM1_RX;
			eDmaReqSrc	= DMA1_PCM1_RX;				
			uDmaSrcAddr	= PCM1_BASE + rPCMRXFIFO;
			usDmaSrcFix	= TRUE;
			eDmaReqDst	= MEM;
			uDmaDstAddr= (u32) pInfor->m_pRecAddr;
			sDmaTransfeSize = pInfor->m_uRecSize/2;
			usDmaDstFix	= FALSE;
		}
		else if ( eIFMode == PCM_TX )
		{	
			eDmaCh		= pInfor->m_eDmaTxCh;
			pPcmDma	= &(pInfor->m_oPcmTxDma);
			eDmaId		= eSEL_PCM1_TX;
			eDmaReqSrc	= MEM;
			eDmaReqDst	= DMA1_PCM1_TX;
			uDmaSrcAddr	= (u32) pInfor->m_pPCMTxAddr;
			sDmaTransfeSize = pInfor->m_uPlaySize/2;
			usDmaSrcFix	= FALSE;			
			uDmaDstAddr= PCM1_BASE + rPCMTXFIFO;
			usDmaDstFix	= TRUE;					
		}
		else
		{
			eDmaCh		= pInfor->m_eDmaRxCh;
			pPcmDma	= &(pInfor->m_oPcmRxDma);
			eDmaId		= eSEL_PCM1_RX;
			eDmaReqSrc	= DMA1_PCM1_RX;	
			uDmaSrcAddr	= PCM1_BASE + rPCMTXFIFO;
			usDmaSrcFix	= TRUE;
			eDmaReqDst	= DMA1_PCM1_TX;
			uDmaDstAddr= DMA1_PCM1_RX + rPCMRXFIFO;
			sDmaTransfeSize = 16;
			usDmaSrcFix	= TRUE;
		}
	}	
	INTC_Enable(pInfor->m_uNumDma);
	if ( pInfor->m_eDmaUnit == SDMA0 ||pInfor->m_eDmaUnit == SDMA1 )
		SYSC_SelectDMA(eDmaId, 0);
	else
		SYSC_SelectDMA(eDmaId, 1);
	DMAC_InitCh(pInfor->m_eDmaUnit , eDmaCh, pPcmDma);
	DMACH_Setup(eDmaCh, false, uDmaSrcAddr, usDmaSrcFix, uDmaDstAddr, usDmaDstFix, HWORD, sDmaTransfeSize, DEMAND, eDmaReqSrc, eDmaReqDst, SINGLE, pPcmDma);
	DMACH_Start(pPcmDma);	
}

//////////
// Function Name : PCM_DMAStop
// Function Description : 
//   This function stops DMA channel for PCM I/F
// Input : 	ePort ->  PCM Controller
//			eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
// Example 
void PCM_DMAStop(AUDIO_PORT ePort, PCM_IFMODE eIFMode)
{
	PCM_Infor* pInfor	 = PCM_GetInfor(ePort);
	DMAC*	pI2SDma;
	if ( eIFMode == PCM_RX )	pI2SDma = &(pInfor->m_oPcmRxDma);
	else if ( eIFMode == PCM_TX )	pI2SDma = &(pInfor->m_oPcmTxDma);
	DMACH_Stop(pI2SDma);	
    	INTC_Disable(pInfor->m_uNumDma);
}

//////////
// Function Name : PCM_SetDMAUnit
// Function Description : This function selec DMA for DMA Request of PCM Interface Contorller.
// Input : 	ePort - I2S Port Number 
//			eUnit - DMA Unit ID
// Output :	None
// Version : v0.0
void PCM_SetDMAUnit(AUDIO_PORT ePort, DMA_UNIT eUnit)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if ( eUnit == DMA0 || eUnit == DMA1 )
	{
		if ( ePort == AUDIO_PORT0 )
		{
			pInfor->m_uNumDma	= NUM_DMA0;					
			pInfor->m_eDmaUnit	= DMA0;		
		}
		else
		{
			pInfor->m_uNumDma	= NUM_DMA1;					
			pInfor->m_eDmaUnit	= DMA1;		
		}			
	}
	else	 if ( eUnit == SDMA0 || eUnit == SDMA1 )
	{
		if ( ePort == AUDIO_PORT0 )
		{
			pInfor->m_uNumDma	= NUM_SDMA0;		
			pInfor->m_eDmaUnit	= SDMA0;		
		}
		else
		{
			pInfor->m_uNumDma	= NUM_SDMA1;		
			pInfor->m_eDmaUnit	= SDMA1;		
		}		
	}
}

//////////
// Function Name : PCM_SetDMACh
// Function Description : This function select DMA Channel for DMA Request of I2S Controller
// Input : 	ePort - I2S Port Number 
//			eUnit - DMA Unit ID
// Output :	None
// Version : v0.0
u8 PCM_SetDMACh(AUDIO_PORT ePort, I2S_IFMode eCh, DMA_CH eDMACh)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if ( eCh == PCM_TX)	pInfor->m_eDmaTxCh = eDMACh;
	else if ( eCh == PCM_RX)	pInfor->m_eDmaRxCh = eDMACh;
	else Assert(0);	
	if ( pInfor->m_eDmaTxCh == pInfor->m_eDmaRxCh)
	{
		UART_Printf("TX, RX Dma Channel is same Channel!!!\n");
		return FALSE;
	}
	else 
		return TRUE;
}

void PCM_PCMInDMA(AUDIO_PORT ePort)
{
	u32 uTempRegister;	
	u32 uSclkDiv, uSyncDiv;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);	
	PCM_InitDMA(ePort, PCM_RX);
	if ( ePort == AUDIO_PORT0)
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_PCMPORT0_PCMIn_DMADone);
	else if ( ePort == AUDIO_PORT1)
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_PCMPORT1_PCMIn_DMADone);
	PCM_GetClkValAndClkDir(ePort, &uSclkDiv, &uSyncDiv);
	PCMCLKCTL_SetDivideLogic(ePort, uSclkDiv, uSyncDiv);	
	PCMCTL_SetDipstick(ePort, PCM_RX, pInfor->m_uTXFIFODipstick);
	PCMCTL_EnableDMA(ePort, PCM_RX, ENABLE);
	PCMCTL_EnableFIFO(ePort, PCM_RX, ENABLE);
	PCMCTL_EnablePCMIF(ePort, ENABLE);
}

void PCM_PCMInDMAStop(AUDIO_PORT ePort)
{
	u32 uTempRegister= 0;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	PCM_DMAStop(ePort, PCM_RX);	
	PCMCTL_EnableDMA(ePort, PCM_RX, DISABLE);
	PCMCTL_EnableFIFO(ePort, PCM_RX, DISABLE);
	PCMCTL_EnablePCMIF(ePort, DISABLE);
	PCMCLKCTL_ActiveDivideLogic(ePort, DISABLE);	
}


void PCM_PCMOutDMAStart(AUDIO_PORT ePort)
{
	u32 uTempRegister;
	u32 uSclkDiv, uSyncDiv;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	// DMA Init
	PCM_InitDMA(ePort, PCM_TX);
	if ( ePort == AUDIO_PORT0)
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_PCMPORT0_PCMOut_DMADone);
	else if ( ePort == AUDIO_PORT1)
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_PCMPORT1_PCMOut_DMADone);	
	//PCM Clock Setting 	
	PCM_GetClkValAndClkDir(ePort, &uSclkDiv, &uSyncDiv);
	PCMCLKCTL_SetDivideLogic(ePort, uSclkDiv, uSyncDiv);
	//Transfer data enable  
	PCMCTL_SetDipstick(ePort, PCM_TX, pInfor->m_uTXFIFODipstick);
	PCMCTL_EnableDMA(ePort, PCM_TX, ENABLE);
	PCMCTL_EnableFIFO(ePort, PCM_TX, ENABLE);
	PCMCTL_EnablePCMIF(ePort, ENABLE);
}

void PCM_PCMOutDMAStop(AUDIO_PORT ePort)
{
	u32 uTempRegister= 0;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	PCM_DMAStop(ePort, PCM_TX);	
	PCMCTL_EnableDMA(ePort, PCM_TX, DISABLE);
	PCMCTL_EnableFIFO(ePort, PCM_TX, DISABLE);
	PCMCTL_EnablePCMIF(ePort, DISABLE);
	PCMCLKCTL_ActiveDivideLogic(ePort, DISABLE);	
}

void PCM_BypassDMA(AUDIO_PORT ePort)
{
	u32 uTempRegister;	
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	PCM_InitDMA(ePort, PCM_RX);
	PCM_InitDMA(ePort, PCM_TX);
	#if 0
	if(ePort == AUDIO_PORT0)
	{
		pInfor->m_eDmaId = eSEL_PCM0_TX;
		pInfor->m_eDmaCh = DMA_B;
		pInfor->m_eDreqSrc = DMA0_PCM0_TX;
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_PCMPORT0_PCMOut_DMADone);
	}
	else if(ePort == AUDIO_PORT1)
	{
		pInfor->m_eDmaId = eSEL_PCM1_TX;
		pInfor->m_eDmaCh = DMA_B;
		pInfor->m_eDreqSrc = DMA1_PCM1_TX;
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_PCMPORT1_PCMOut_DMADone);
	}
	
	//IRQ Setting
	INTC_Enable(pInfor->m_uNumDma);
	

	//DMA Setting
   	SYSC_SelectDMA(pInfor->m_eDmaId, 1);
    	DMAC_InitCh(pInfor->m_eDmaUnit, pInfor->m_eDmaCh, &g_oPcmDma);

    	DMACH_ClearIntPending(&g_oPcmDma);
	DMACH_ClearErrIntPending(&g_oPcmDma);
	DMACH_Setup(pInfor->m_eDmaCh, 0x0, (u32)pInfor->m_uPcmRxFifoAddr, true, 
					pInfor->m_uPcmTxFifoAddr, true, HWORD, pInfor->m_uRecSize/4, 
					HANDSHAKE, MEM, pInfor->m_eDreqSrc , SINGLE, &g_oPcmDma);	
  	
    	DMACH_Start(&g_oPcmDma);
	#endif

	//PCM Clock Setting 
	
	//Transfer data enable  
	uTempRegister = PCM_Inp32(ePort, rPCMCTRL);
	uTempRegister |= TXFIFO_DIPSTICK(0x8) | PCMCTL_EN_TX_DMA |PCMCTL_EN_TX_FIFO |PCMCTL_EN_RX_DMA |PCMCTL_EN_RX_FIFO |PCMCTL_EN_PCMIF;
	PCM_Outp32(ePort, rPCMCTRL, uTempRegister);		
}

void PCM_PCMInInt(AUDIO_PORT ePort)
{
	u32 uTempRegister = 0, uIRQRegiset = 0;
	u32 uSclkDiv, uSyncDiv;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);		
	//IRQ Initialization
	//Disable PCM IRQ to ARM
	uIRQRegiset = PCM_Inp32(ePort,  rPCMIRQCTL);
	uIRQRegiset &= ~PCMIRQ_Enable_IRQ_TO_ARM;
	PCM_Outp32(ePort, rPCMIRQCTL, uIRQRegiset);
	
	INTC_ClearVectAddr();
	
	if(ePort == AUDIO_PORT0)
		INTC_SetVectAddr(pInfor->m_uNumInt, Isr_PCMPORT0_PCMIn);
	
	else if(ePort == AUDIO_PORT1)
		INTC_SetVectAddr(pInfor->m_uNumInt, Isr_PCMPORT1_PCMIn);	
	
	INTC_Enable(pInfor->m_uNumInt);	
	
	PCM_ClearInt(ePort);														// Clear Interrupt	
	#if 0
	PCMIRQCTL_SetIRQMode(ePort, PCMIRQALL, false);								// Disable another Interrupt Condition
	PCMIRQCTL_SetIRQMode(ePort, RX_FIFO_ALMOST_FULL, true);					// Set Irq condition when RX FIFO ALMOST Full	
	PCMIRQCTL_EnableInt(ePort, ENABLE);										// Enable IRQ Gen'
	#else
	PCMIRQCTL_EnableInt(ePort, TRUE);										// Enable Interrupt 
	#endif

	// PCM CLK and Divider Enable
	PCM_GetClkValAndClkDir(ePort, &uSclkDiv, &uSyncDiv);
	PCMCLKCTL_SetDivideLogic(ePort, uSclkDiv, uSyncDiv);	
	
	//Transfer data enable  
	uTempRegister = PCM_Inp32(ePort, rPCMCTRL);
	uTempRegister |= RXFIFO_DIPSTICK(0x20) | PCM_RXFIFO_EN  |PCMCTL_EN_PCMIF & ~PCM_TXFIFO_EN & ~PCMCTL_EN_RX_DMA;
	PCM_Outp32(ePort, rPCMCTRL, uTempRegister);
	
	UART_Printf("Now Recoding....\n");
	PCMIRQCTL_GetIRQMode(ePort);
	pInfor->m_pMemI2SRx = pInfor->m_pRecAddr;
	pInfor->m_usAC97PCMInDone = FALSE;
	while(1)
	{

		if(pInfor->m_usAC97PCMInDone)
			break;	
	}
	INTC_Disable(pInfor->m_uNumInt);
	PCMIRQCTL_EnableInt(ePort, FALSE);   	
    	PCMCTL_EnablePCMIF(ePort,  false);	
	UART_Printf("\nEnd of Record!\n");
}


void PCM_PCMOutInt(AUDIO_PORT ePort)
{
	u32 uTempRegister, uIRQRegiset = 0;
	u32 uSclkDiv, uSyncDiv;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	//IRQ Initialization
	uIRQRegiset = PCM_Inp32(ePort,  rPCMIRQCTL);
	uIRQRegiset &= ~PCMIRQ_Enable_IRQ_TO_ARM;
	PCM_Outp32(ePort, rPCMIRQCTL, uIRQRegiset);
	INTC_ClearVectAddr();
	
	if(ePort == AUDIO_PORT0)
		INTC_SetVectAddr(pInfor->m_uNumInt, Isr_PCMPORT0_PCMOut);
	
	else if(ePort == AUDIO_PORT1)
		INTC_SetVectAddr(pInfor->m_uNumInt, Isr_PCMPORT1_PCMOut);
	INTC_Enable(pInfor->m_uNumInt);
  
	PCM_ClearInt(ePort);

	// Interrupt
	#if 0
	PCMIRQCTL_SetIRQMode(ePort, PCMIRQALL, false);								// Disable another Interrupt Condition
	PCMIRQCTL_SetIRQMode(ePort, TXFIFO_ALMOST_EMPTY, true);						// Set Irq condition when RX FIFO ALMOST Full
	PCMIRQCTL_EnableInt(ePort, ENABLE);											// Enable IRQ Gen'
	#else
	//PCMIRQCTL_SetIRQ(ePort);												// Set Interrupt Condition	
	PCMIRQCTL_EnableInt(ePort, TRUE);										// Enable Interrupt 
	#endif 
	
	//PCM Clock Setting 
	PCM_GetClkValAndClkDir(ePort, &uSclkDiv, &uSyncDiv);
	PCMCLKCTL_SetDivideLogic(ePort, uSclkDiv, uSyncDiv);
	
	uTempRegister = PCM_Inp32(ePort, rPCMCTRL);
	uTempRegister = TXFIFO_DIPSTICK(0x14) |PCM_TXFIFO_EN|PCMCTL_EN_PCMIF;
	//Transfer data enable  
	PCM_Outp32(ePort, rPCMCTRL,  uTempRegister);
	UART_Printf("Now Playing....\n");
	PCMIRQCTL_GetIRQMode(ePort);
	pInfor->m_pMemI2STx = pInfor->m_pPCMTxAddr;
	pInfor->m_usAC97PCMOutDone = FALSE;	
	while(1)
	{
		if(pInfor->m_usAC97PCMOutDone)
			break;	
	}
	INTC_Disable(pInfor->m_uNumInt);
	PCMIRQCTL_EnableInt(ePort, false);   	
   	PCMCTL_EnablePCMIF(ePort,  false);	
	//PCM_DisableInt();

	UART_Printf("\nEnd of Play!\n");
}




/////////////////////////////////////////////// ISR of PCM I/F ///////////////////////////////////////////////
void __irq Isr_PCMPORT0_PCMIn_DMADone(void)
{
	PCM_DMADone(AUDIO_PORT0, PCM_RX);
}

void __irq Isr_PCMPORT0_PCMIn_DMARestart(void)
{
	PCM_DMARestart(AUDIO_PORT0, PCM_RX);
}

void __irq Isr_PCMPORT0_PCMOut_DMADone(void)
{
	PCM_DMARestart(AUDIO_PORT0, PCM_TX);
}

void __irq Isr_PCMPORT1_PCMIn_DMADone(void)
{
	PCM_DMADone(AUDIO_PORT1, PCM_RX);
}

void __irq Isr_PCMPORT1_PCMIn_DMARestart(void)
{
	PCM_DMARestart(AUDIO_PORT1, PCM_RX);
}
void __irq Isr_PCMPORT1_PCMOut_DMADone(void)
{
	PCM_DMARestart(AUDIO_PORT1, PCM_TX);
}

void __irq Isr_PCMPORT0_PCMIn(void)
{
	PCM_IsrDataIn(AUDIO_PORT0);
}

void __irq Isr_PCMPORT0_PCMOut(void)
{
	PCM_IsrDataOut(AUDIO_PORT0);
}

void __irq Isr_PCMPORT1_PCMIn(void)
{
	PCM_IsrDataIn(AUDIO_PORT1);
}
void __irq Isr_PCMPORT1_PCMOut(void)
{
	PCM_IsrDataOut(AUDIO_PORT1);
}

void __irq Isr_PCM0_Bypass(void)
{
	PCM_Infor* pInfor = PCM_GetInfor(AUDIO_PORT0);
	DMA_CH eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oPcmRxDma));
	INTC_Disable(pInfor->m_uNumDma);
	if ( eReqCh & pInfor->m_eDmaRxCh )
		PCM_DMARestart(AUDIO_PORT0, PCM_RX);	
	if ( eReqCh & pInfor->m_eDmaTxCh )
		PCM_DMARestart(AUDIO_PORT0, PCM_TX);			
	INTC_ClearVectAddr();
}

void __irq Isr_PCM1_Bypass(void)
{
	PCM_Infor* pInfor = PCM_GetInfor(AUDIO_PORT1);
	DMA_CH eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oPcmRxDma));
	INTC_Disable(pInfor->m_uNumDma);
	if ( eReqCh & pInfor->m_eDmaRxCh )
		PCM_DMARestart(AUDIO_PORT1, PCM_RX);	
	if ( eReqCh & pInfor->m_eDmaTxCh )
		PCM_DMARestart(AUDIO_PORT1, PCM_TX);			
	INTC_ClearVectAddr();
}

void PCM_DMADone(AUDIO_PORT ePort, PCM_IFMODE eCh)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	INTC_Disable(pInfor->m_uNumDma);
	UART_Printf("\nPCM0 In DMA Done.\n");
	if ( eCh == PCM_RX)
	{
		pInfor->m_usAC97PCMInDone = TRUE;
		DMACH_ClearIntPending(&(pInfor->m_oPcmRxDma));
		DMACH_ClearErrIntPending(&(pInfor->m_oPcmRxDma));
	}
	else if ( eCh == PCM_TX)
	{
		pInfor->m_usAC97PCMOutDone = TRUE;
		DMACH_ClearIntPending(&(pInfor->m_oPcmTxDma));
		DMACH_ClearErrIntPending(&(pInfor->m_oPcmTxDma));
	}
	INTC_ClearVectAddr();	

}

void PCM_DMARestart(AUDIO_PORT ePort, PCM_IFMODE eCh)
{
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	DMAC*		pPcmDma;
	INTC_Disable(pInfor->m_uNumDma);
	PCMCTL_EnableDMA(ePort, eCh, DISABLE);
	PCMCTL_EnableFIFO(ePort, eCh, DISABLE);
	PCM_InitDMA(ePort, eCh);
	if ( eCh == PCM_TX )
	{
		UART_Printf("\nPCM%d TX Channel DMA Transfer Restart.\n", (u32) ePort);
		pPcmDma = &(pInfor->m_oPcmTxDma);
	}
	else if ( eCh == PCM_RX )
	{
		UART_Printf("\nPCM%d RX ChannelDMA Transfer Restart.\n", (u32) ePort);
		pPcmDma = &(pInfor->m_oPcmRxDma);
	}
	
	DMACH_ClearIntPending(pPcmDma);
	DMACH_ClearErrIntPending(pPcmDma);
	PCMCTL_EnableFIFO(ePort, eCh, ENABLE);
	PCMCTL_EnableDMA(ePort, eCh, ENABLE);
	INTC_ClearVectAddr();	
}

void PCM_IsrDataIn(AUDIO_PORT ePort)
{
	u32 i; 
	u32 uFifoCnt;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	u16* pTemp;
	INTC_Disable(pInfor->m_uNumInt);
	INTC_ClearVectAddr();
	PCM_ClearInt(ePort);		
	uFifoCnt = PCMFIFO_GetCnt(ePort, PCM_RX);
	for(i=0; i<uFifoCnt; i++)
	{
		pTemp = PCM_PutDataMem(ePort, PCM_RX, PCMFIFO_GetData(ePort, PCM_RX));
		if( (u32) pTemp  >=  ((u32)  pInfor->m_pRecAddr +(u32)  pInfor->m_uRecSize) )
			break;	
	}
	if( (u32) pTemp  >=  ((u32)  pInfor->m_pRecAddr +(u32)  pInfor->m_uRecSize) )
		pInfor->m_usAC97PCMInDone = TRUE;		
	PCM_ClearInt(ePort);
	INTC_Enable(pInfor->m_uNumInt);
}

void PCM_IsrDataOut(AUDIO_PORT ePort)
{
	u32 i; 
	u32 uFifoCnt;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	INTC_Disable(pInfor->m_uNumInt);
	INTC_ClearVectAddr();
	PCM_ClearInt(ePort);
	uFifoCnt = PCMFIFO_GetCnt(ePort, PCM_TX);		
	for(i=0; i< (32-uFifoCnt); i++)
	{
		PCMFIFO_PutData(ePort, PCM_TX, PCM_PopDataMem(ePort, PCM_TX));
		if( (u32) pInfor->m_pMemI2STx >=  ((u32)  pInfor->m_pPCMTxAddr +(u32)  pInfor->m_uPlaySize) )
			break;	
	}
	if( (u32) pInfor->m_pMemI2STx >=  ((u32)  pInfor->m_pPCMTxAddr +(u32)  pInfor->m_uPlaySize) )
		pInfor->m_usAC97PCMOutDone = TRUE;			
	INTC_Enable(pInfor->m_uNumInt);
}
/////////////////////////////////////////////// API of PCM I/F ///////////////////////////////////////////////
//////////
// Function Name : PCMCTL_PutData
// Function Description : 
//   This function implements put data into PCMCTL along with PCM Information Sturucture.
// Input : 	ePort		- PCM I/F controller number
// Output : NONE
// Version : v0.1
void PCMCTL_PutData(AUDIO_PORT ePort)
{
	u32 urPCMCTL = 0;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	urPCMCTL = PCM_Inp32(ePort, rPCMCTRL);
	urPCMCTL &= ~(0x3f << 13) & ~(0x3f << 7) & ~(0x3 << 3);	
	urPCMCTL |= (pInfor->m_uTXFIFODipstick & 0x3f) << 13 | (pInfor->m_uRXFIFODipstick & 0x3f) << 7;
	if (pInfor->m_eTXMSBPosition == AFTER_PCMSYNC_HIGH)
		urPCMCTL |= (1 << 4) | (1 << 3);
	else 
		urPCMCTL &= ~(1 << 4) &  ~(1 << 3);		
	PCM_Outp32(ePort, rPCMCTRL, urPCMCTL);
}

//////////
// Function Name : PCMCTL_SetDipstick
// Function Description : 
//   This function implements set FIFO Dipstick.
// Input : 	ePort		- PCM I/F controller number
// 			eCh			- TX/RX Channel
// 			usDipstick	- Dipsitck
// Output : NONE
// Version : v0.1
void PCMCTL_SetDipstick(AUDIO_PORT ePort, PCM_IFMODE eCh, u8 usDipstick)
{
	u32 urPCMCTL = 0;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	urPCMCTL = PCM_Inp32(ePort, rPCMCTRL);
	if ( eCh == PCM_TX )
	{
		pInfor->m_uTXFIFODipstick = usDipstick;
		urPCMCTL = urPCMCTL & ~(0x3f << 13) | (usDipstick & 0x3f) << 13;
		
	}
	else if ( eCh == PCM_RX )
	{
		pInfor->m_uRXFIFODipstick = usDipstick;
		urPCMCTL = urPCMCTL & ~(0x3f << 7) | (usDipstick & 0x3f) << 7;
	}
	else
	{
		pInfor->m_uTXFIFODipstick = usDipstick;
		pInfor->m_uRXFIFODipstick = usDipstick;
		urPCMCTL = urPCMCTL & ~(0x3f << 13) & ~(0x3f << 7) | ((usDipstick & 0x3f) << 13) | ((usDipstick & 0x3f) << 7);
	}
	PCM_Outp32(ePort, rPCMCTRL, urPCMCTL);
}

//////////
// Function Name : PCMCTL_SetMSBPosition
// Function Description : 
//   This function implements set PCM MSB position of interface Channel.
// Input : 	ePort		- PCM I/F controller number
// 			eCh			- TX/RX Channel
// 			eMSBPos	- MSBPosition
// Output : NONE
// Version : v0.1
void PCMCTL_SetMSBPosition(AUDIO_PORT ePort, PCM_IFMODE eCh, SerialDataFormat eMSBPos)
{
	u32 urPCMCTL = 0;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	urPCMCTL = PCM_Inp32(ePort, rPCMCTRL);
	if ( eCh == PCM_TX )
	{
		pInfor->m_eTXMSBPosition = eMSBPos;
		if (eMSBPos == AFTER_PCMSYNC_HIGH)		urPCMCTL |= (1 << 4);
		else 									urPCMCTL &= ~(1 << 4);		
	}
	else if ( eCh == PCM_RX )
	{
		pInfor->m_eRXMSBPosition = eMSBPos;
		if (eMSBPos == AFTER_PCMSYNC_HIGH)		urPCMCTL |= (1 << 3);
		else 									urPCMCTL &= ~(1 << 3);		
	}
	else
	{
		pInfor->m_eTXMSBPosition = eMSBPos;
		pInfor->m_eRXMSBPosition = eMSBPos;
		if (eMSBPos == AFTER_PCMSYNC_HIGH)		urPCMCTL |= (1 << 4) | (1 << 3);
		else 									urPCMCTL &= ~(1 << 4) &  ~(1 << 3);		
	}
	PCM_Outp32(ePort, rPCMCTRL, urPCMCTL);
}

//////////
// Function Name : PCMCTL_EnablePCMIF
// Function Description : 
//   This function implements enable PCM I/F.
// Input : 	ePort		- PCM I/F controller number
// 			uActive		- Enable/Disable
// Output : NONE
// Version : v0.1
void PCMCTL_EnablePCMIF(AUDIO_PORT ePort,   u8 uActive)
{
	u32 urPCMCTL = 0;
	urPCMCTL = PCM_Inp32(ePort, rPCMCTRL);
	if (uActive == true)
		urPCMCTL |= PCMCTL_EN_PCMIF;
	else 
		urPCMCTL &= ~PCMCTL_EN_PCMIF;
	PCM_Outp32(ePort, rPCMCTRL, urPCMCTL);
}

//////////
// Function Name : PCMCTL_EnableDMA
// Function Description : 
//   This function implements enable DMA Request of PCM I/F.
// Input : 	ePort			- PCM I/F controller number
// 			rhs_eIFMode	- Tx/Rx
// 			uActive			- Enable/Disable
// Output : NONE
// Version : v0.1
void PCMCTL_EnableDMA(AUDIO_PORT ePort,  PCM_IFMODE rhs_eIFMode, u8 uActive)
{
	u32 urPCMCTL = 0;
	urPCMCTL = PCM_Inp32(ePort, rPCMCTRL);
	if (rhs_eIFMode == PCM_TX)
	{
		if (uActive == true)
			urPCMCTL |= PCMCTL_EN_TX_DMA;
		else 
			urPCMCTL &= ~PCMCTL_EN_TX_DMA;
	}
	else if (rhs_eIFMode == PCM_RX)
	{
		if (uActive == true)
			urPCMCTL |= PCMCTL_EN_RX_DMA;
		else 
			urPCMCTL &= ~PCMCTL_EN_RX_DMA;
	}
	else if (rhs_eIFMode == PCM_TXRX)
	{
		if (uActive == true)
			urPCMCTL |= PCMCTL_EN_TX_DMA | PCMCTL_EN_RX_DMA;
		else 
			urPCMCTL &= ~PCMCTL_EN_TX_DMA & ~PCMCTL_EN_RX_DMA;
	}
	
	PCM_Outp32(ePort, rPCMCTRL, urPCMCTL);
}

//////////
// Function Name : PCMCTL_EnableFIFO
// Function Description : 
//   This function implements enable FIFO read/write.
// Input : 	ePort			- PCM I/F controller number
// 			rhs_eIFMode	- Tx/Rx
// 			uActive			- Enable/Disable
// Output : NONE
// Version : v0.1
void PCMCTL_EnableFIFO(AUDIO_PORT ePort, PCM_IFMODE rhs_eIFMode, u8 uActive)
{
	u32 urPCMCTL = 0;
	urPCMCTL = PCM_Inp32(ePort, rPCMCTRL);
	if (rhs_eIFMode == PCM_TX)
	{
		if (uActive == true)
			urPCMCTL |= PCMCTL_EN_TX_FIFO;
		else 
			urPCMCTL &= ~PCMCTL_EN_TX_FIFO;
	}
	else if (rhs_eIFMode == PCM_RX)
	{
		if (uActive == true)
			urPCMCTL |= PCMCTL_EN_RX_FIFO;
		else 
			urPCMCTL &= ~PCMCTL_EN_RX_FIFO;
	}
	else if (rhs_eIFMode == PCM_TXRX)
	{
		if (uActive == true)
			urPCMCTL |= PCMCTL_EN_TX_FIFO | PCMCTL_EN_RX_FIFO;
		else 
			urPCMCTL &= ~PCMCTL_EN_TX_FIFO & ~PCMCTL_EN_RX_FIFO;
	}	
	PCM_Outp32(ePort, rPCMCTRL, urPCMCTL);
}


//////////
// Function Name : PCMCLKCTL_SetDivideLogic
// Function Description : 
//   This function implements Enabe Divider Logic, Put SCLK_DIV and SYNC_DIV value and select source of PCMSCLK
// Input : 	ePort		- PCM I/F controller number
// 			uSclkDiv	- PCMSCLK Divider Value
// 			uSyncDiv	- PCMSYNC Divider Value
// Output : NONE
// Version : v0.1
void PCMCLKCTL_SetDivideLogic(AUDIO_PORT ePort, u32 uSclkDiv, u32  uSyncDiv)
{
	u32 urPCMCLKCTL = 0;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if (pInfor->m_ePCMClkSrc == PCM_PCLK)
		urPCMCLKCTL = PCMCLK_EN_DivideLogic | (1 << 18) | (uSclkDiv << 9) | (uSyncDiv << 0);
	else 
		urPCMCLKCTL = PCMCLK_EN_DivideLogic | (0 << 18) | (uSclkDiv << 9) | (uSyncDiv << 0);
	PCM_Outp32(ePort, rPCMCLKCTL, urPCMCLKCTL);
}

//////////
// Function Name : PCM_SelCLKAUDIO
// Function Description : 
//   This function implements Select Clock Source of PCM I/F.
// Input : 	ePort		- PCM I/F controller number
// 			eClkSrc		- Clock Source.
// Output : NONE
// Version : v0.1
void PCM_SelCLKAUDIO(AUDIO_PORT ePort, PCM_CLKSRC eClkSrc)
{
	u32 urPCMCLKCTL = PCM_Inp32(ePort, rPCMCLKCTL) & ~PCMCLK_SERCLKSEL;
	if(ePort == AUDIO_PORT0)
	{
		if(eClkSrc == PCM_MOUT_EPLL) 		SYSC_ClkSrc(eAUDIO0_MOUTEPLL);				
		else if (eClkSrc == PCM_DOUT_MPLL) 	SYSC_ClkSrc(eAUDIO0_DOUTMPLL);
		else if (eClkSrc == PCM_FIN_EPLL) 		SYSC_ClkSrc(eAUDIO0_FINEPLL);
		else if (eClkSrc == PCM_PCMCDCLK) 	SYSC_ClkSrc(eAUDIO0_PCMCDCLK);
		else 								urPCMCLKCTL |= PCMCLK_SERCLKSEL;
	}
	else if(ePort == AUDIO_PORT1)
	{
		if(eClkSrc == PCM_MOUT_EPLL) 		SYSC_ClkSrc(eAUDIO1_MOUTEPLL);			
		else if (eClkSrc == PCM_DOUT_MPLL) 	SYSC_ClkSrc(eAUDIO1_DOUTMPLL);
		else if (eClkSrc == PCM_FIN_EPLL) 		SYSC_ClkSrc(eAUDIO1_FINEPLL);
		else if (eClkSrc == PCM_PCMCDCLK) 	SYSC_ClkSrc(eAUDIO1_PCMCDCLK);
		else 								urPCMCLKCTL |= PCMCLK_SERCLKSEL;
	}
	else Assert("0");
	PCM_Outp32(ePort, rPCMCLKCTL, urPCMCLKCTL);
}

//////////
// Function Name : PCMCLKCTL_ActiveDivideLogic
// Function Description : 
//   This function implements enable/disable Divider Logic of PCM I/F.
// Input : 	ePort		- PCM I/F controller number
// 			uActive		- Enable or Disable
// Output : NONE
// Version : v0.1
void PCMCLKCTL_ActiveDivideLogic(AUDIO_PORT ePort, u8 uActive)
{
	u32 urPCMCLKCTL = 0;
	urPCMCLKCTL = PCM_Inp32(ePort, rPCMCLKCTL);
	if (uActive == true)
		urPCMCLKCTL |= 1 << 19 ;
	else 
		urPCMCLKCTL &= ~(1 << 19);
	PCM_Outp32(ePort, rPCMCLKCTL, urPCMCLKCTL);
}

//////////
// Function Name : PCMCLKCTL_SetSclkDivVal
// Function Description : 
//   This function implements Set SCLKDIV Value.
// Input : 	ePort		- PCM I/F controller number
// 			uSclkDiv	- SCLK Divider Value
// Output : NONE
// Version : v0.1
void PCMCLKCTL_SetSclkDivVal(AUDIO_PORT ePort, u32 uSclkDiv)
{
	u32 urPCMCLKCTL = 0;
	urPCMCLKCTL = PCM_Inp32(ePort, rPCMCLKCTL);
	urPCMCLKCTL &= ~(0xff << 9);
	urPCMCLKCTL |= (uSclkDiv <<9);
	PCM_Outp32(ePort, rPCMCLKCTL, urPCMCLKCTL);
}

//////////
// Function Name : PCMCLKCTL_SetSyncDivVal
// Function Description : 
//   This function implements Set SCLKDIV Value.
// Input : 	ePort		- PCM I/F controller number
// 			uSyncDiv	- SYNC Divider Value
// Output : NONE
// Version : v0.1
void PCMCLKCTL_SetSyncDivVal(AUDIO_PORT ePort, u32 uSyncDiv)
{
	u32 urPCMCLKCTL = 0;
	urPCMCLKCTL = PCM_Inp32(ePort, rPCMCLKCTL);
	urPCMCLKCTL &= ~(0x1ff << 0);
	urPCMCLKCTL |= (uSyncDiv <<0);
	PCM_Outp32(ePort, rPCMCLKCTL, urPCMCLKCTL);
}

//////////
// Function Name : PCMTXFIFO_GetValid
// Function Description : 
//   This function implements get data validation.
// Input : 	ePort		- PCM I/F controller number
// 			eCh			- TX/RX
// Output : u8
// Version : v0.1
u8 PCMFIFO_GetValid(AUDIO_PORT ePort, PCM_IFMODE eCh)
{
	u32 urPCMFIFO;
	if ( eCh == PCM_TX)		urPCMFIFO = PCM_Inp32(ePort, rPCMTXFIFO);
	else if ( eCh == PCM_RX)	urPCMFIFO = PCM_Inp32(ePort, rPCMRXFIFO);
	else 	Assert(0);
	if ((urPCMFIFO & (1 << 16)))
		return TRUE;
	else
		return FALSE;
}

//////////
// Function Name : PCMTXFIFO_GetValid
// Function Description : 
//   This function implements get data validation.
// Input : 	ePort		- PCM I/F controller number
// 			eCh			- TX/RX
// Output : u16			- FIFO Data
// Version : v0.1
u16 PCMFIFO_GetData(AUDIO_PORT ePort, PCM_IFMODE eCh)
{
	if ( eCh == PCM_TX)		return PCM_Inp16(ePort, rPCMTXFIFO);
	else if ( eCh == PCM_RX)	return PCM_Inp16(ePort, rPCMRXFIFO);
	else 	Assert(0);
}


//////////
// Function Name : PCMTXFIFO_GetValid
// Function Description : 
//   This function implements get data validation.
// Input : 	ePort		- PCM I/F controller number
// 			eCh			- TX/RX
// Output : u16			- FIFO Data
// Version : v0.1
void PCMFIFO_PutData(AUDIO_PORT ePort, PCM_IFMODE eCh, u16 uData)
{
	if ( eCh == PCM_TX)		PCM_Outp16(ePort, rPCMTXFIFO, uData);
	else if ( eCh == PCM_RX)	PCM_Outp16(ePort, rPCMRXFIFO, uData);
	else 	Assert(0);
}

//////////
// Function Name : PCMIRQCTL_EnableInt
// Function Description : 
//   This function implements enable/disable Interrup of PCM I/F.
// Input : 	ePort		- PCM I/F controller number
// 			rhs_uActive	- enable/disable
// Output : NONE
// Version : v0.1
void PCMIRQCTL_EnableInt(AUDIO_PORT ePort, u8 rhs_uActive)
{
	u32 urPCMIRQCTL = PCM_Inp32(ePort, rPCMIRQCTL) & ~PCMIRQ_Enable_IRQ_TO_ARM;
	if (rhs_uActive == true)
		urPCMIRQCTL |= PCMIRQ_Enable_IRQ_TO_ARM;
	else 
		urPCMIRQCTL &= ~PCMIRQ_Enable_IRQ_TO_ARM;
	PCM_Outp32(ePort, rPCMIRQCTL, urPCMIRQCTL);
}


//////////
// Function Name : PCMIRQCTL_SetIRQMode
// Function Description : 
//   This function implements Select Interrupt Condition.
// Input : 	ePort		- PCM I/F controller number
// 			rhs_ePcmInt	- Interrupt Condition.
// 			rhs_uActive	- Enable/Disable
// Output : NONE
// Version : v0.1
void PCMIRQCTL_SetIRQMode(AUDIO_PORT ePort, PCM_INT rhs_ePcmInt,  u8 rhs_uActive)
{
	u32 urPCMIRQCTL = PCM_Inp32(ePort, rPCMIRQCTL);
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	if (rhs_uActive == true)	
		urPCMIRQCTL |= rhs_ePcmInt;
	
	else 	
		urPCMIRQCTL &= ~(rhs_ePcmInt);	
	pInfor->m_uIntAspects = urPCMIRQCTL;
	PCM_Outp32(ePort, rPCMIRQCTL, urPCMIRQCTL);
}

//////////
// Function Name : PCMIRQCTL_GetIRQMode
// Function Description : 
//   This function implements display Interrupt Condition and return PCMIRQCTL
// Input : 	ePort		- PCM I/F controller number
// Output : u32			- PCMIRQCTL Value.
// Version : v0.1
u32 PCMIRQCTL_GetIRQMode(AUDIO_PORT ePort)
{
	u32 urPCMIRQCTL = PCM_Inp32(ePort, rPCMIRQCTL);	 
	u32 uTest = 0;
	s32 sLoopCnt = 12;
	s32 sCnt;
	u32 uIntCondition = (1 << sLoopCnt);
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	for ( sCnt = sLoopCnt; sCnt != 0;sCnt--)
	{
		Disp("Interrupt Condition\n");
		if (uIntCondition == TRANSFER_DONE)				Disp("\nTransfer Done");
		else if (uIntCondition == TXFIFO_EMPTY)			Disp("\nTX FIFO Empty");
		else if (uIntCondition == TXFIFO_ALMOST_EMPTY)	Disp("TX FIFO Almost Empty");
		else if (uIntCondition == TXFIFO_FULL)				Disp("TX FIFO Full");
		else if (uIntCondition == TXFIFO_ALMOST_FULL)		Disp("TX FIFO Almost Full");
		else if (uIntCondition == TXFIFO_ERROR_STARVE)		Disp("TX FIFO Starve Error");
		else if (uIntCondition == TXFIFO_ERROR_OVERFLOW)	Disp("TX FIFO Overflow Error");
		else if (uIntCondition == RXFIFO_EMPTY)			Disp("\nRX FIFO Empty");
		else if (uIntCondition == RXFIFO_ALMOST_EMPTY)	Disp("RX FIFO Almost Empty");
		else if (uIntCondition == RX_FIFO_FULL)				Disp("RX FIFO Full");
		else if (uIntCondition == RX_FIFO_ALMOST_FULL)		Disp("RX FIFO Alomst Full");
		else if (uIntCondition == RXFIFO_ERROR_STARVE)		Disp("RX FIFO Starve Error");
		else if (uIntCondition == RXFIFO_ERROR_OVERFLOW)	Disp("RX FIFO Overflow Error");
		uTest = urPCMIRQCTL & uIntCondition;
		if (uTest)
			Disp("0\t");
		else
			Disp("X\t");
		uIntCondition = (1 << sCnt);
	}
	pInfor->m_uIntAspects = urPCMIRQCTL;
	return urPCMIRQCTL;
}


//////////
// Function Name : PCMIRQCTL_GetIRQMode
// Function Description : 
//   This function implements display Interrupt Pending and return PCMIRQSTAT Value.
// Input : 	ePort		- PCM I/F controller number
// Output : u32			- PCMIRQSTAT Value.
// Version : v0.1
u32 PCMIRQSTAT_GetIRQState(AUDIO_PORT ePort)
{
	u32 urPCMIRQCTL = PCM_Inp32(ePort, rPCMIRQSTAT);	 
	u32 uTest = 0;
	s32 sLoopCnt = 13;
	s32 sCnt;
	u32 uIntCondition = (1 << sLoopCnt);	
	for ( sCnt = sLoopCnt; sCnt != 0;sCnt--)
	{
		Disp("Interrupt Condition\n");
		if (uIntCondition == PCMIRQPENDING)				Disp("\nPCM IRQ");
		else if (uIntCondition == TRANSFER_DONE)			Disp("\nTransfer Done");
		else if (uIntCondition == TXFIFO_EMPTY)			Disp("\nTX FIFO Empty");
		else if (uIntCondition == TXFIFO_ALMOST_EMPTY)	Disp("TX FIFO Almost Empty");
		else if (uIntCondition == TXFIFO_FULL)				Disp("TX FIFO Full");
		else if (uIntCondition == TXFIFO_ALMOST_FULL)		Disp("TX FIFO Almost Full");
		else if (uIntCondition == TXFIFO_ERROR_STARVE)		Disp("TX FIFO Starve Error");
		else if (uIntCondition == TXFIFO_ERROR_OVERFLOW)	Disp("TX FIFO Overflow Error");
		else if (uIntCondition == RXFIFO_EMPTY)			Disp("\nRX FIFO Empty");
		else if (uIntCondition == RXFIFO_ALMOST_EMPTY)	Disp("RX FIFO Almost Empty");
		else if (uIntCondition == RX_FIFO_FULL)				Disp("RX FIFO Full");
		else if (uIntCondition == RX_FIFO_ALMOST_FULL)		Disp("RX FIFO Alomst Full");
		else if (uIntCondition == RXFIFO_ERROR_STARVE)		Disp("RX FIFO Starve Error");
		else if (uIntCondition == RXFIFO_ERROR_OVERFLOW)	Disp("RX FIFO Overflow Error");
		uTest = urPCMIRQCTL & uIntCondition;
		if (uTest)
			Disp("0\t");
		else
			Disp("X\t");
		uIntCondition = (1 << sCnt);
	}
	return urPCMIRQCTL;
}


//////////
// Function Name : PCM_ClearInt
// Function Description : 
//   This function implements return FIFO Count of  PCM I/F Channel.
// Input : 		ePort	- PCM I/F controller number
//				eCH		- TX/RX
// Output : 	u32		- FIFO count
// Version : v0.1
u8 PCMFIFO_GetCnt(AUDIO_PORT ePort, PCM_IFMODE eCH)
{
	u32 uPcmFifoStat = PCM_Inp32(ePort, rPCMFIFOSTAT);
	if ( eCH == PCM_TX) 
		return ((uPcmFifoStat & (0x3f << 14))>>14);
	else if ( eCH == PCM_RX) 
		return ((uPcmFifoStat & (0x3f << 4))>>4);
	else 
		Assert(0);
}

//////////
// Function Name : PCM_ClearInt
// Function Description : 
//   This function implements return FIFO Count of  PCM I/F Channel.
// Input : 		ePort	- PCM I/F controller number
//				eCH		- TX/RX
// Output : 	u8		- FIFO State
// Version : v0.1
u8 PCMFIFO_GetState(AUDIO_PORT ePort, PCM_IFMODE eCH)
{
	u32 uPcmFifoStat = PCM_Inp32(ePort, rPCMFIFOSTAT);	
	if ( eCH == PCM_TX) 
		return ((uPcmFifoStat & (0xf << 10))>>10);
	else if ( eCH == PCM_RX) 
		return ((uPcmFifoStat & (0xf << 0))>>0);
	else 
		Assert(0);
}
//////////
// Function Name : PCM_ClearInt
// Function Description : 
//   This function implements clear Interrupt Pendding of PCM I/F.
// Input : 	ePort		- PCM I/F controller number
// Version : v0.1
void PCM_ClearInt(AUDIO_PORT ePort)
{
	PCM_Outp32(ePort, rPCMCLRINT, 0x1);
}


//////////
// Function Name : PCM_GetClkValAndClkDir
// Function Description : 
//   This function implements get SCLK DIV Value and Sync DIV Value
// Input : 	ePort		- PCM I/F controller number
//			uSclkDiv	- Address of Return SCLKDIV
//			uSyncDiv	- Address of Return SYNCDIV
// Version : v0.1
void PCM_GetClkValAndClkDir(AUDIO_PORT ePort, u32* uSclkDiv, u32* uSyncDiv)
{
	double dTempVal, dVclkSrc, dVclkSync;
	PCM_Infor* pInfor = PCM_GetInfor(ePort);
	SYSC_GetClkInform();
	switch(pInfor->m_ePCMClkSrc)
	{
		case PCM_MOUT_EPLL:
			dVclkSrc = I2S_SetEPLL(ePort, (double)(pInfor->m_uSamplingRate * 256));
			UART_Printf("Source CLK is AudioCLK%d, Epll : %3.3fMHz\n",(u32) ePort, dVclkSrc/1000000);
			break;
		case PCM_DOUT_MPLL:
			dVclkSrc = (double) (g_MPLL);
			UART_Printf("Source CLK is AudioCLK%d, Mpll : %3.3fMHz\n",(u32) ePort, dVclkSrc/1000000);
			break;
		case PCM_FIN_EPLL:
			dVclkSrc =  FIN; 
			UART_Printf("Source CLK is AudioCLK%d, Fin of Pll : %3.3fMHz\n",(u32) ePort, dVclkSrc/1000000);
			break;
		case PCM_PCMCDCLK:
			dVclkSrc = I2S_EXTERNALCLK;	
			UART_Printf("Source CLK is AudioCLK%d, External clk of PCMCDCLK : %3.3fMHz\n",(u32) ePort, dVclkSrc/1000000);
			break;
		case PCM_PCLK:
			dVclkSrc = (double) (g_PCLK);
			UART_Printf("Source CLK is PCLK : %3.3fMHz\n", dVclkSrc/1000000);
			break;
	}
	dTempVal = dVclkSrc/(double)(2*pInfor->m_uPCMSClk) - 1;
	if ( ((int)(dTempVal*10) % 10) < 5)		//Round off 
		dTempVal = dTempVal-1;
	*uSclkDiv = (int)(dTempVal + 1);
	dVclkSync = dVclkSrc/(2 * ( (*uSclkDiv) + 1));
	dTempVal = (double)pInfor->m_uPCMSClk / (double)pInfor->m_uSamplingRate - 1;
	if ( ((int)(dTempVal*10) % 10) < 5)		//Round off 
		dTempVal = dTempVal-1;
	*uSyncDiv = (int)(dTempVal + 1);
	UART_Printf("User Set PCMSCLK : %dHz\n",(pInfor->m_uPCMSClk/1000));
	UART_Printf("User Set PCMSYNC(Sampling Frequency : %dHz\n",(pInfor->m_uSamplingRate));
	UART_Printf("SCLK DIV : %d\n",*uSclkDiv);
	UART_Printf("Current PCMSCLK : %dHz\n", (u32) dVclkSync);
	UART_Printf("SYNC DIV : %d\n",*uSyncDiv);
	UART_Printf("Current PCMSCLK : %3.1fKHz\n", (dVclkSync/( ( (*uSyncDiv) + 1) ))/1000);	
 }


